home *** CD-ROM | disk | FTP | other *** search
- // ---------------- btree.cpp
-
- #include <string.h>
- #include "parody.h"
-
- // ---------- constructor to open a btree
- Btree::Btree(Index& ndx, Key *ky) :
- index(ndx), LinkedListEntry(NULL)
- {
- currnode = 0;
- trnode = NULL;
- nullkey = ky->Make();
- nullkey->Key::operator=(*ky);
- NodeNbr nd = 0;
- int clno = ky->classid;
-
- if (!index.NewFile()) {
- Node node(&index, 1);
- // ------- locate the class header
- while (clno) {
- NodeNbr nx = node.NextNode();
- if (nx == 0) {
- // need to link this one with new one(s) added
- nd = index.NewNode();
- node.SetNextNode(nd);
- break;
- }
- node = Node(&index, nx);
- --clno;
- }
- if (clno == 0) {
- // ------ position to the tree header
- index.Nfile().seekg((long)
- (ky->indexno * sizeof(TreeHeader)), ios::cur);
- headeraddr = index.Nfile().tellp();
- // ------- read the btree header
- index.Nfile().read((char *)
- &header, sizeof(TreeHeader));
- return;
- }
- }
- // ------- build the class headers for new node or class
- index.ResetNewFile();
- if (nd == 0)
- nd = index.NewNode();
- else
- --clno;
- TreeHeader th;
- const int treect = nodedatalength / sizeof(TreeHeader);
- while (clno) {
- Node node(&index, nd);
- for (int i = 0; i < treect; i++)
- index.Nfile().write((char*)&th,sizeof(TreeHeader));
- nd = index.NewNode();
- node.SetNextNode(nd);
- --clno;
- }
-
- Node node(&index, nd);
- // ------ position to the tree header
- for (int i = 0; i < ky->indexno; i++)
- index.Nfile().write((char *)&th, sizeof(TreeHeader));
- headeraddr = index.Nfile().tellp();
- // ------- write the btree header
- index.Nfile().write((char *)&header, sizeof(TreeHeader));
- // ------- pad out the rest of the node
- for (i++; i < treect; i++)
- index.Nfile().write((char *)&th, sizeof(TreeHeader));
- // ----- pad any residual node space
- int residual = nodedatalength-treect*sizeof(TreeHeader);
- if (residual) {
- char *residue = new char[residual];
- memset(residue, 0, residual);
- index.Nfile().write(residue, residual);
- delete residue;
- }
- node.MarkNodeChanged();
- }
-
- // ---------- destructor for a btree
- Btree::~Btree()
- {
- index.Nfile().seekg(headeraddr);
- index.Nfile().write((char *)&header, sizeof(TreeHeader));
- delete nullkey;
- }
-
- // ---------------- insert a key into a btree
- void Btree::Insert(void *keypointer)
- {
- // ---- don't insert duplicate keys
- if (!Find(keypointer)) {
-
- Key *newkey = ((Key *)keypointer)->Make();
- *newkey = *(Key *)keypointer;
-
- NodeNbr rootnode = 0, leftnode = 0, rightnode = 0;
- pBool RootisLeaf = pTrue;
-
- pBool done = pFalse;
- // -------- insert key into btree
- while (currnode) {
- int em = trnode->m();
- trnode->Insert(newkey);
- // first insertion is into leaf
- // if split, subsequent insertions
- // are into parents (non-leaves)
- if (!trnode->header.isleaf)
- trnode->currkey->lowernode = rightnode;
-
- done = (pBool) (trnode->header.keycount <= em);
- if (!done)
- // ---- node is full,
- // try to redistribute keys among siblings
- done = trnode->Redistribute(
- trnode->header.leftsibling);
- if (!done)
- done = trnode->Redistribute(
- trnode->header.rightsibling);
-
- if (done)
- break;
- // ---- cannot redistribute filled node, split it
- RootisLeaf = pFalse;
-
- rightnode = index.NewNode();
- leftnode = currnode;
-
- TNode right(this, rightnode);
- right.SetNodeNbr(rightnode);
- right.MarkNodeChanged();
-
- // --- establish sibling and parent relationships
- // between current node and new right sibling
- right.header.rightsibling =
- trnode->header.rightsibling;
- trnode->header.rightsibling = rightnode;
- right.header.leftsibling = currnode;
- right.header.parent = trnode->header.parent;
-
- // ----- if the current node is a leaf,
- // so is the new sibling
- right.header.isleaf = trnode->header.isleaf;
-
- // ----- compute new key counts for the two nodes
- trnode->header.keycount = (em + 1) / 2;
- right.header.keycount = em-trnode->header.keycount;
-
- // ------ locate the middle key in the current node
- Key *middlekey = (Key *)
- (trnode->keys.FirstListEntry());
- for (int i = 0; i < trnode->header.keycount; i++)
- middlekey = (Key *) middlekey->NextListEntry();
-
- // ---- set the pointer to keys less than
- // those in new node
- if (!right.header.isleaf)
- right.header.lowernode = middlekey->lowernode;
-
- // ----- point to the keys to move (1 past middle)
- Key *movekey = (Key *) middlekey->NextListEntry();
-
- // ----- middle key inserts into parent
- middlekey->DeleteListEntry();
- *newkey = *middlekey;
- delete middlekey;
-
- // ---- move keys from current to new right node
- for (i = 0; i < right.header.keycount; i++) {
- Key *nkey = (Key *) movekey->NextListEntry();
- movekey->DeleteListEntry();
- movekey->AppendListEntry(&right.keys);
- movekey = nkey;
- }
-
- // ---- prepare to insert key
- // into parent of split nodes
- currnode = trnode->header.parent;
- if (!currnode) {
- // ---- no parent node, splitting the root node
- rootnode = index.NewNode();
- right.header.parent = rootnode;
- trnode->header.parent = rootnode;
- }
-
- // --- the former right sibling of the current node
- // is now the right sibling of the split node
- // and must record the new node as left sibling
-
- if (right.header.rightsibling) {
- TNode farright(this, right.header.rightsibling);
- farright.header.leftsibling = rightnode;
- farright.MarkNodeChanged();
- }
-
- // --- children of the new split node point to
- // the current split node as parent. They must
- // be adopted by the new split node
-
- if (!right.header.isleaf)
- right.Adoption();
-
- // ----- if splitting other than root, read parent
- // position currkey to key where split node
- // key will be inserted
-
- if (currnode) {
- delete trnode; // writes the split node to disk
- // --- get the parent of the split nodes
- trnode = new TNode(this, currnode);
- // -- position currkey where new key will insert
- trnode->SearchNode(newkey);
- }
- }
-
- if (!done) {
- // ------ new root node ------ */
- delete trnode;
- if (rootnode == 0)
- rootnode = index.NewNode();
- trnode = new TNode(this, rootnode);
- trnode->header.isleaf = RootisLeaf;
- currnode = header.rootnode = rootnode;
- trnode->SetNodeNbr(rootnode);
- trnode->Insert(newkey);
- trnode->header.parent = 0;
- trnode->header.keycount = 1;
- if (!RootisLeaf) {
- trnode->header.lowernode = leftnode;
- trnode->currkey->lowernode = rightnode;
- }
- trnode->MarkNodeChanged();
- }
- delete newkey;
- }
- delete trnode;
- trnode = NULL;
- }
-
- // ---------------- find a key in a btree
- pBool Btree::Find(void *keypointer)
- {
- currnode = header.rootnode;
- while (currnode) {
- delete trnode;
- trnode = new TNode(this, currnode);
-
- if (trnode->SearchNode((Key *)keypointer)) {
- // ---- search key is equal to a key in the node
- ((Key*)keypointer)->fileaddr =
- trnode->currkey->fileaddr;
- return pTrue;
- }
- if (trnode->header.isleaf)
- break;
- if (trnode->currkey == trnode->keys.FirstListEntry())
- // ---- search key is < lowest key in node
- currnode = trnode->header.lowernode;
- else if (trnode->currkey)
- // --- search key is < current key in node
- currnode = ((Key *)
- (trnode->currkey->PrevListEntry()))->lowernode;
- else
- // --- search key is > highest key in node
- currnode =
- ((Key *)(trnode->keys.LastListEntry()))->lowernode;
- }
- return pFalse;
- }
-
- // ---------------- delete a key from a btree
- void Btree::Delete(void *keypointer)
- {
- if (Find(keypointer)) {
- if (!trnode->header.isleaf) {
-
- // --- if not found in leaf node, go down to leaf
- TNode *leaf =
- new TNode(this, trnode->currkey->lowernode);
- while (!leaf->header.isleaf) {
- NodeNbr lf = leaf->header.lowernode;
- delete leaf;
- leaf = new TNode(this, lf);
- }
-
- // ---- Move the left-most key from the leaf
- // to where deleted key was in higher node
- Key *movekey = (Key *) leaf->keys.FirstListEntry();
- movekey->DeleteListEntry();
- leaf->header.keycount--;
- leaf->MarkNodeChanged();
-
- movekey->InsertListEntry(
- trnode->currkey, &trnode->keys);
- movekey->lowernode = trnode->currkey->lowernode;
- trnode->currkey->DeleteListEntry();
- delete trnode->currkey;
- trnode->MarkNodeChanged();
- delete trnode;
-
- trnode = leaf;
- trnode->currkey =
- (Key *) trnode->keys.FirstListEntry();
- currnode = trnode->GetNodeNbr();
- }
- else {
- // ---- delete the key from the node
- trnode->currkey->DeleteListEntry();
- delete trnode->currkey;
- trnode->header.keycount--;
- trnode->MarkNodeChanged();
- if (trnode->header.keycount == 0)
- header.rootnode = 0;
- }
- // ---- if the node shrinks to half capacity,
- // try to combine it with a sibling node
- while (trnode->header.keycount > 0 &&
- trnode->header.keycount <= trnode->m() / 2) {
- if (trnode->header.rightsibling) {
- TNode *right =
- new TNode(this, trnode->header.rightsibling);
- if (trnode->Implode(*right)) {
- delete right;
- NodeNbr parent = trnode->header.parent;
- if (parent == 0) {
- header.rootnode = trnode->GetNodeNbr();
- break;
- }
- delete trnode;
- trnode = new TNode(this, parent);
- continue;
- }
- delete right;
- }
- if (trnode->header.leftsibling) {
- TNode *left =
- new TNode(this, trnode->header.leftsibling);
- if (left->Implode(*trnode)) {
- delete trnode;
- NodeNbr parent = left->header.parent;
- if (parent == 0) {
- header.rootnode = left->GetNodeNbr();
- trnode = left;
- break;
- }
- delete left;
- trnode = new TNode(this, parent);
- continue;
- }
- delete left;
- }
-
- // --- could not combine with either sibling,
- // try to redistribute
- if (!trnode->Redistribute(
- trnode->header.leftsibling))
- trnode->Redistribute(
- trnode->header.rightsibling);
- break;
- }
- }
- delete trnode;
- trnode = NULL;
- }
-
- // ------ return the address of the current key
- Key *Btree::Current()
- {
- if (trnode == NULL)
- return NULL;
- return trnode->currkey;
- }
-
- // ------ return the address of the first key
- Key *Btree::First()
- {
- currnode = header.rootnode;
- if (currnode) {
- delete trnode;
- trnode = new TNode(this, currnode);
- while (!trnode->header.isleaf) {
- currnode = trnode->header.lowernode;
- delete trnode;
- trnode = new TNode(this, currnode);
- }
- trnode->currkey =
- (Key *) (trnode->keys.FirstListEntry());
- }
- return Current();
- }
-
- // ------ return the address of the last key
- Key *Btree::Last()
- {
- currnode = header.rootnode;
- if (currnode) {
- delete trnode;
- trnode = new TNode(this, currnode);
- while (!trnode->header.isleaf) {
- currnode =
- ((Key *)(trnode->keys.LastListEntry()))->
- lowernode;
- delete trnode;
- trnode = new TNode(this, currnode);
- }
- trnode->currkey =
- (Key *) (trnode->keys.LastListEntry());
- }
- return Current();
- }
-
- // ------ return the address of the next key
- Key *Btree::Next()
- {
- if (trnode == NULL || trnode->currkey == NULL)
- return First();
- if (!trnode->header.isleaf) {
- // --- current key is not in a leaf
- currnode = trnode->currkey->lowernode;
- delete trnode;
- trnode = new TNode(this, currnode);
- // ----- go down to the leaf
- while (!trnode->header.isleaf) {
- currnode = trnode->header.lowernode;
- delete trnode;
- trnode = new TNode(this, currnode);
- }
- // ---- use the first key in the leaf as the next one
- trnode->currkey =
- (Key *) (trnode->keys.FirstListEntry());
- }
- else {
- // ------ current key is in a leaf
- Key *thiskey = nullkey->Make();
- *thiskey = *(trnode->currkey);
-
- // ----- point to the next key in the leaf
- trnode->currkey =
- (Key *) (trnode->currkey->NextListEntry());
- while (trnode->currkey == NULL &&
- currnode != header.rootnode) {
- // --- current key was the last one in the leaf
- TNode pnode(this, trnode->Parent());
- pnode.SearchNode(thiskey);
- currnode = pnode.GetNodeNbr();
- *trnode = pnode;
- }
- delete thiskey;
- }
- return Current();
- }
-
- // ------ return the address of the previous key
- Key *Btree::Previous()
- {
- if (trnode == NULL || trnode->currkey == NULL)
- return Last();
- if (!trnode->header.isleaf) {
- // --- current key is not in a leaf
- Key *ky = (Key *) (trnode->currkey->PrevListEntry());
- if (ky != NULL)
- currnode = ky->lowernode;
- else
- currnode = trnode->header.lowernode;
- delete trnode;
- trnode = new TNode(this, currnode);
- // ----- go down to the leaf
- while (!trnode->header.isleaf) {
- currnode =
- ((Key *)
- (trnode->keys.LastListEntry()))->lowernode;
- delete trnode;
- trnode = new TNode(this, currnode);
- }
- // ---- use the last key in the leaf as the next one
- trnode->currkey =
- (Key *) (trnode->keys.LastListEntry());
- }
- else {
- // ------ current key is in a leaf
- Key *thiskey = nullkey->Make();
- *thiskey = *(trnode->currkey);
-
- // ----- point to the previous key in the leaf
- trnode->currkey =
- (Key *) (trnode->currkey->PrevListEntry());
- while (trnode->currkey == NULL &&
- currnode != header.rootnode) {
- // --- current key was the first one in the leaf
- TNode pnode(this, trnode->Parent());
- pnode.SearchNode(thiskey);
- if (pnode.currkey == NULL)
- pnode.currkey =
- (Key *) pnode.keys.LastListEntry();
- else
- pnode.currkey =
- (Key *) (pnode.currkey->PrevListEntry());
- currnode = pnode.GetNodeNbr();
- *trnode = pnode;
- }
- delete thiskey;
- }
- return Current();
- }
-
-